using System;
using System.IO;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;


namespace NCover
{
	using Objects;

	/// <summary>
	/// Holds the raw data for what coverage points have been hit / missed.
	/// </summary>
	public class Coverage
	{	
		public const string EXPECTED_EXTENSION = "-expected.xml";

		public readonly static XmlSerializer SERIALIZER = new XmlSerializer(typeof(Coverage));


		[XmlAttribute()]
		public string Type;

		public Counter Counter;

		public CoveragePoint[] CoveragePoints;

		[XmlIgnore()]
		public CoveragePoint[] MissedCoveragePoints
		{
			get 
			{
				ArrayList misses = new ArrayList();
				
				NCover.NCoverCheck.Add(180); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(180); NCover.NCoverCheck.Add(180); NCover.NCoverCheck.Add(179); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); foreach ( CoveragePoint point in CoveragePoints)
				{
					if (!point.Hit && NCover.NCoverCheck.Add(187) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(187) && NCover.NCoverCheck.Add(187) && NCover.NCoverCheck.Add(186) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188))
						misses.Add(point);
				}

				NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(180); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); return (CoveragePoint[]) misses.ToArray(typeof(CoveragePoint));
			}
		}

		/// <summary>
		/// Saves the expected coverage
		/// </summary>
		public static void SaveCoverage(Stream expected, Coverage coverage)
		{
			using (TextWriter writer = new StreamWriter(expected))
			{
				SERIALIZER.Serialize(new XmlTextWriter(writer), coverage);
			}
		}			

		/// <summary>
		/// re-Generates coverage given before / after streams.
		/// </summary>
		public static Coverage LoadCoverage(Stream expected, Stream [] actuals)
		{
			Coverage coverage = null;
			using (TextReader reader = new StreamReader(expected))
			{
				coverage = (Coverage) SERIALIZER.Deserialize(new XmlTextReader(reader));
			}
			
			//actuals could be spread accross several files.
			foreach (Stream actual in actuals)
			{
				SetHits(coverage, LoadActualCoverage(actual));
			}

			NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(181); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); return coverage;
		}

		/// <summary>
		/// for test purposes this has been broken out and exposed.
		/// </summary>
		public static Coverage LoadActualCoverage(Stream actual)
		{
			NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(182); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); return (Coverage) SERIALIZER.Deserialize(
				new XmlTextReader(new StringReader(TerminateActualXmlFile(actual))));
		}

		/// <summary>
		/// We do this as we like xml files, but we don't like finalizers as we're
		/// not sure if / when they run and they're a bit dodge so best to close off the
		/// actualCoveragePoints xml file upon reading.
		/// </summary>
		private static string TerminateActualXmlFile(Stream actualFilename)
		{
			string contents = null;
			using (StreamReader reader = new StreamReader(actualFilename))
			{
				contents = reader.ReadToEnd().Trim();
				if (!contents.EndsWith("</Coverage>") && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(190))
					contents += "</CoveragePoints></Coverage>";
			}
			NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(183); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); return contents;
		}

		/// <summary>
		/// This sets the 'Hit' property on the expected coverage points to true if the coverage
		/// point exists in the actual coverage file.
		/// 
		/// The net effect is you can then discard the actual coverage file as all the information
		/// is in the expected coverage.
		/// </summary>
		private static void SetHits(Coverage expectedCoverage, Coverage actualCoverage)
		{
			int hitCount = 0;
			NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(184); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); foreach (CoveragePoint actualPoint in actualCoverage.CoveragePoints)
			{
				NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(188); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(186); NCover.NCoverCheck.Add(185); NCover.NCoverCheck.Add(188); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); NCover.NCoverCheck.Add(187); foreach (CoveragePoint expected in expectedCoverage.CoveragePoints)
				{
					if (expected.Equals(actualPoint) && !expected.Hit && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(191) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(188) && NCover.NCoverCheck.Add(187) && NCover.NCoverCheck.Add(190) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189) && NCover.NCoverCheck.Add(189))
					{
						expected.Hit = true;
						hitCount++;
					}
				}
			}

			System.Diagnostics.Debug.Assert(hitCount <= actualCoverage.CoveragePoints.Length);
		}

	}
}














